#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <stdio.h>

using namespace std;

template<class T>
void print_vector(const vector<T>& v)
{
    typename vector<T>::const_iterator it = v.begin();
    //从属名称:template内出现的名称,如果依赖于template中的参数
    //那么它就是一个从属名称
    //而如果它同时又嵌套于模板参数中,那么它就是嵌套从属名称
    //我这个是const_iterator是模板中出现的名称
    //同时又依赖于模板参数T,同时const_iterator又嵌套于模板参数中
    //所以const_interator就是一个嵌套从属名称
    
    //C++中有一个解析规则：如果解析器在template中遇到一个嵌套的从属名称
    //那么便假设这个名称不是一个类型
    //除非通过增加关键字typename来告诉它是一个类型。

    while(it != v.end())
    {
        cout << *it << " ";
        ++it;
    }
    cout << endl;
}

void test_vector1()
{
    //无参构造
    vector<int> first;
    //初始化4个250
    vector<int> second(4,250);
    //根据迭代器区间来进行初始化
    vector<int> third(second.begin() + 1, second.end() - 1);
    //拷贝构造
    vector<int> fourth(third);

    //vector<char>能替换string吗?
    //不能,比如string结尾会有'\0'
    //string支持+=,而vector不支持+=
    //string可以进行大小比较,而vector不行......
    string s("hellw world");
    vector<char> fifth(s.begin(), s.end());
}

void test_vector2()
{
    vector<int> v;
    v.push_back(1);
    v.push_back(2);
    v.push_back(3);
    v.push_back(4);
    v.push_back(5);

    //下标遍历
    for (size_t i = 0; i < v.size(); ++i)
    {
        v[i] += 1;
        cout << v[i] << " ";
    }
    cout << endl;

    //迭代器遍历
    vector<int>::iterator it = v.begin();
    while(it != v.end())
    {
        *it -= 1;
        cout << *it << " ";
        ++it;
    }
    cout << endl;

    //迭代器反向遍历
    vector<int>::reverse_iterator rit = v.rbegin();
    while(rit != v.rend())
    {
        *rit += 2;
        cout << *rit << " ";
        ++rit;
    }
    cout << endl;

    //范围for遍历
    for(int e : v)
    {
        e -= 2;
        cout << e << " ";
    }
    cout << endl;

    //数组有迭代器吗?
    //没有,但是数组的指针是被认为是天然的迭代器,所以没有给数组设置迭代器
    //数组也是支持范围for的,会被替换成指针
    
    char arr[] = {"liulun233!"};

    //范围for会被替换成下面那种带指针的形式
    for(char e : arr)
    {
        cout << e;
    }
    cout << endl;

    for (char* p = arr; p < arr + sizeof(arr) / sizeof(char); ++p)
    {
        cout << *p;
    }
    cout << endl;

}

void test_vector3()
{
    vector<char> v1;
    vector<int> v;
    v.push_back(1);
    v.push_back(2);
    v.push_back(3);
    v.push_back(4);
    v.push_back(5);
    
    //查看vector的大小
    cout << v.size() << endl;

    //查看vector的最大大小
    //你会发现vector<int>和vector<char>的最大大小不一样
    //因为int = 4 char的大小
    cout << v.max_size() << endl;
    cout << v1.max_size() << endl;

    //查看vector的容量
    cout << v.capacity() << endl;

    //vecotr的扩容
    //只负责扩大容量,缩小会进行无视
    v.reserve(20);

    //vector的扩容 + 初始化
    //负责扩大容量,缩小也会进行删除数据,但不会减少容量
    v.resize(25, 250);
    v.resize(10);

    //判断这个vector是否为空
    //1代表空,0代表不空
    cout << v.empty() << endl;
    cout << v1.empty() << endl;
    
    //下面我们来看看linux下capacity的变化是如何的
    //通过结果可以看出,linux上是以标准的2倍进行增长
    //vs是以近似1.5倍进行增长
    cout << '\n' << '\n' << endl;
    vector<int> v_t;
    cout << "initial capacity:" << v_t.capacity() << endl;
    size_t sz = v_t.capacity();
    for(size_t i = 0; i < 500; ++i)
    {
        v_t.push_back(250);
        if(sz != v_t.capacity())
        {
            sz = v_t.capacity();
            cout << "capacity has changed:" << sz << endl;
        }
    }
}

void test_vector4()
{
    vector<int> v;
    v.push_back(1);
    v.push_back(2);
    v.push_back(3);
    v.push_back(4);
    v.push_back(5);

    //访问下标为i的元素,vs上越界采取断言的方式
    cout << v[0] << endl;
    //cout << v[10] << endl;

    //访问下标为i的元素,越界采取抛异常的方式
    cout << v.at(1) << endl;
    //cout << v.at(10) << endl;

    //访问第一个元素
    cout << v.front() << endl;
     v.front() += 1;
    cout << v.front() << endl;

    //访问最后一个元素
    cout << v.back() << endl;
    v.back() -= 1;
    cout << v.back() << endl;
}

void test_vector5()
{
    vector<int> v;

    v.push_back(1);
    v.push_back(2);
    v.push_back(3);
    v.push_back(4);
    v.push_back(5);

    //分配vector内容,将新内容赋给vector,替换当前内容,并相应的修改大小
    //在调用之前容器中保存的所有元素都会被销毁
    //并被新构造的元素替换(不会对元素进行赋值)。
    //当(且仅当)新vector大小超过当前vector容量时
    //会自动重新分配已分配的存储空间。
    //如果发生重新分配，则使用内部分配器(内存池)分配所需的存储。
    
    //第一个使用形式:
    //新内容为2个元素,每个元素初始值化为250
    //lenth = 2, capacity = 5
    v.assign(2, 250);

    //第二种使用形式:
    //新内容为迭代器区间初始化的内容
    //注意这个区间是左闭右开
    //lenth = 10, capacity = 10
    int arr[] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14};
    v.assign(arr, arr + 10);

    //清空vector中所有元素,lenth不变
    v.clear();

    //vector尾插元素
    v.push_back(1);
    v.push_back(2);
    v.push_back(3);
    v.push_back(4);
    vector<int>::iterator it = v.begin();
    for (; it != v.end(); ++it)
    {
        cout << *it << " ";
    }
    cout << endl;

    //vector尾删元素
    v.pop_back();
    v.pop_back();

    it = v.begin();
    for (; it != v.end(); ++it)
    {
        cout << *it << " ";
    }
    cout << endl;

    //vector任意位置插入元素
    //通过迭代器的位置插入元素
    v.insert(v.begin() + 1 , 250);
    print_vector(v);

    //通过迭代器的位置插入n个元素
    v.insert(v.begin() + 2, 5, 100);
    print_vector(v);

    //通过迭代器范围插入元素
    vector<int> v1(8, 666);
    v.insert(v.begin(), v1.begin() + 2, v1.end() - 1);
    print_vector(v);
    
    //通过迭代器位置删除元素
    v.erase(v.begin() + 5);
    print_vector(v);

    //通过迭代器范围删除元素
    v.erase(v.begin() + 5, v.end() - 1);
    print_vector(v);

    //将两个vector的内容进行交换
    cout << "v:";
    print_vector(v);
    cout << "v1:";
    print_vector(v1);
    v.swap(v1);
    cout << "v:";
    print_vector(v);
    cout << "v1:";
    print_vector(v1);

    //vector为什么没有像string那样实现find函数?
    //因为一般容器都是查找一个值,那么后面的list和deque......也需要查找
    //那么就可以抽取出来(在algorithm文件中),因为都可以根据迭代器进行查找
    //string需要实现find是因为string有时需要查找字串
    
    //根据迭代器区间寻找位置,最后返回迭代器的位置
    //如果没有找到,那么就返回迭代器区间的最后位置
    vector<int>::iterator ret = find(v1.begin(), v1.end(), 2);
    if(ret != v1.end())
    {
        cout << "v1中的元素找到了,删除后,变为:";
        v1.erase(ret);
        print_vector(v1);
    }
}

int main()
{
    //构造函数
    //test_vector1();
    
    //迭代器iterator
    //test_vector2();

    //空间容量
    test_vector3();

    //元素访问
    //test_vector4();
    
    //元素修改
    // test_vector5();
    return 0;
}
